﻿using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;

namespace GKS.DataTypes.Math.Numbers {
    public abstract class Number : INumber {
        #region variables
        
        #endregion

        #region properties
        //public Signs Sign { get; set; }
        #endregion

        #region enums
        public enum Signs { Negative, Positive };
        #endregion

        #region constructors

        #endregion

        #region methods
        public INumber Add(INumber another) {
            if (another is Number) {
                return this + (Number)another;
            }

            throw new ArgumentException(
                "The given parameter is not an instance of Number.",
                "another");
        }

        public INumber Subtract(INumber another) {
            if (another is Number) {
                return this - (Number)another;
            }

            throw new ArgumentException(
                "The given parameter is not an instance of Number.",
                "another");
        }

        public INumber Multiply(INumber another) {
            if (another is Number) {
                return this * (Number)another;
            }

            throw new ArgumentException(
                "The given parameter is not an instance of Number.",
                "another");
        }

        public INumber Divide(INumber another) {
            if (another is Number) {
                return this / (Number)another;
            }

            throw new ArgumentException(
                "The given parameter is not an instance of Number.",
                "another");
        }

        public abstract Number Add(Number another);

        public Number Add(Number another, params Number[] others) {
            Number result = this + another;

            foreach (Number n in others) {
                result += n;
            }

            return result;
        }

        public abstract Number Subtract(Number another);

        public Number Subtract(Number another, params Number[] others) {
            Number result = this - another;

            foreach (var n in others) {
                result -= n;
            }

            return result;
        }

        public abstract Number Multiply(Number another);

        //public Number Multiply(Number another, params Number[] others) {
        //    Number result = this * another;

        //    foreach (var n in others) {
        //        result *= n;
        //    }

        //    return result;
        //}

        public abstract Number Divide(Number another);

        //public Number Divide(Number another, params Number[] others) {
        //    Number result = this / another;

        //    foreach (var n in others) {
        //        result = result.Divide(n);
        //    }

        //    return result;
        //}

        //public Number Divide(Number another, out Number modulus) {
        //    Number divisionResult = this / another;
        //    modulus = this - (divisionResult * another);

        //    return divisionResult;
        //}

        //public Number Modulus(Number another) {
        //    Number result = null;
        //    Divide(another, out result);

        //    return result;
        //}

        public abstract bool Equals(Number another);

        public override bool Equals(object obj) {
            return (obj is Number) ? this.Equals((Number)obj) : false;
        }

        public abstract string ToString(int representationBase);
        #endregion

        #region operators
        #region mathematical operators
        public static Number operator +(Number first, Number second) {
            return first.Add(second);
        }

        public static Number operator -(Number first, Number second) {
            return first.Subtract(second);
        }

        public static INumber operator *(Number first, Number second) {
            return first.Multiply(second);
        }

        public static INumber operator /(Number first, Number second) {
            return first.Divide(second);
        }
        #endregion

        #region boolean operators
        public static bool operator ==(Number first, Number second) {
            return first.Equals(second);
        }

        public static bool operator !=(Number first, Number second) {
            return !(first == second);
        }
        #endregion
        #endregion
    }
}
